import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;



public class Main {

	
	public static int randInt(int min, int max) { //generates a random number between min and max, inclusive
		
	    Random rand = new Random();
	    
	    int randomNum = rand.nextInt((max - min) + 1) + min;

	    return randomNum;
	};
	
	
    public static void writeLinesToFile(String filename,
            String[] linesToWrite,
            boolean appendToFile) {

  	  		PrintWriter pw = null;

  	  		try {

  	  			if (appendToFile) {

  	  				//If the file already exists, start writing at the end of it.
  	  				pw = new PrintWriter(new FileWriter(filename, true));

  	  			}
  	  			else {

  	  				pw = new PrintWriter(new FileWriter(filename));
  	  				//this is equal to:
  	  				//pw = new PrintWriter(new FileWriter(filename, false));

  	  			}

  	  			for (int i = 0; i < linesToWrite.length; i++) {

  	  				pw.println(linesToWrite[i]);

  	  			}
  	  			pw.flush();

  	  		}
  	  		catch (IOException e) {
  	  			e.printStackTrace();
  	  		}	
  	  		finally {

  	  			//Close the PrintWriter
  	  			if (pw != null)
  	  				pw.close();

  	  		}
} 
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		int usercount = -1;
		int contentcount = -1;
		int timesteps = -1;
		
		User [] userarray;
		int [] useronline;
		
                int [][] c_likedby_u;
                                int [][] u_like_nrc;

                
		if (args.length == 3) {
		    try {
		    	
		        usercount = Integer.parseInt(args[0]);
		        contentcount = Integer.parseInt(args[1]);
		        timesteps = Integer.parseInt(args[2]);
		        
		    } catch (NumberFormatException e) {
		        System.err.println("Arguments must be an integer.");
		        
		        System.exit(1);
		    }
		} else {
			
			  System.err.println("3 Arguments expected (integer): number of users, contents, timesteps");
		        
		        System.exit(1);
		    }
			
		
		
		if ((usercount>0) && (contentcount>0) && (timesteps>0)) {
			
			System.out.println("Welcome!");

			//Initialization 
			userarray = new User[usercount]; 
			useronline = new int[usercount];
			
                        c_likedby_u = new int[timesteps+1][usercount+1];
                        u_like_nrc = new int[timesteps+1][contentcount+1];    
                        
			for(int i = 0; i < usercount ; i++) {
				
				userarray[i] = new User(usercount);
				useronline[i] = 0;
				
				//???THB add one random c to ?each? User i
				
				int c=randInt(1, contentcount);
				User curUser = userarray[i];
				curUser.addToL(c); //i  c
				userarray[i] = curUser;
				System.out.println(c+" zufall");
			}
		
			/*			Assign only 1 random c to first user (0) */
			/* 
			int c=randInt(1, contentcount);
			User curUser = userarray[0];
				curUser.addToL(c);
			userarray[0] = curUser;
			System.out.println("Content " + c + " added to user 0.");
			*/
			
			//main loop
			for (int ts=1; ts<=timesteps; ts++) {
				
				//user U loop
				for (int u=0; u<usercount; u++) {
					
					if (useronline[u]<=0) {  //user is offline (not online)
						
						//Random online time
						int A = randInt(1, 20);
						useronline[u] = A;
						
					//	System.out.println(A);	
						
						User curUseru=userarray[u];
						curUseru.resetUsersToConsiderforR();
						userarray[u]=curUseru;
						
						for (int rusercount=0; rusercount<A; rusercount++)
						{
                                                    int newrandomruserfound = 0;
                                                    User curUseru2=userarray[u];

                                                        while(newrandomruserfound==0) {
							int selectedruser = randInt(0, usercount-1);
							
                                                        if (!curUseru2.getListUsersToConsiderforR().contains(selectedruser))
                                                        {
							curUseru2.addToUsersToConsiderforR(selectedruser);
							userarray[u]=curUseru2;
                                                        newrandomruserfound=1;
                                                        } else {
                                                            newrandomruserfound = 0;
                                                        }
                                                        }
						}
						
						
                                                
                                                
                                                
                                                User curUser = userarray[u];
					
					List curRList = curUser.getListUsersToConsiderforR();
					
					for (int v=0; v<curRList.size(); v++ ) {
						
						int curRUser = ((int) curRList.get(v));
						
					//	if (v!=u) {//THB Fehler
                                                if(curRUser!=u) {
						//System.out.println("curuser " + u + "  " + v);
                                                    
						//	User curUserV= userarray[v]; //THB Fehler
                                                        User curUserV= userarray[curRUser];
	
                                                
                                                
							int likedLast = curUserV.likedLast();
							
							if (likedLast!=-1) {
								
								int decideAddToRofUserU = randInt(0,1);
								if (decideAddToRofUserU==1) {
									User curUserU = userarray[u];
									
									curUserU.pushToR(likedLast);
							//		System.out.println("Pushed " + likedLast + " to user " +u);

									
									userarray[u]=curUserU;
									
								} 

							}
							
							
						}
						
						
					} //push to user u's R list
                                                
						
						
						
					} //user u offline
					
					
					if (useronline[u]>0)
					{  //user is online
						useronline[u]=useronline[u]-1; //decrease remaining online time
						
						//Update L(u)
						User curUserU=userarray[u];
						int poppedrecommendation = curUserU.popFromR();
						//System.out.println(poppedrecommendation);
						
						if (poppedrecommendation!=-1) {
							
							int decideAddToL = randInt(0,1);
							
						//	System.out.println("DecideAddToL " +decideAddToL + " Content: " +poppedrecommendation);
							
							if (decideAddToL==1) {
								curUserU.addToL(poppedrecommendation);
							}
							
						}
						userarray[u]=curUserU;
						
						
					} //user online

				} //user U loop
				
                        } //timesteps   //or further down when for each timestep a log is needed 
                                
                                
                                
                          /*Output of results*/

			
			
			//print Size of L(u) and R(u) after simulation; Output Format: User,L(u),R(u)
			String logfile = "user_numberoflikes_numberofrecos_"+System.currentTimeMillis()+"_"+usercount+"_"+contentcount+"_"+timesteps+"_simresults.log";
			
			System.out.println("Output Format: User, size of L(u), size of R(u)");
			
			for (int u=0; u<usercount; u++) {
				User curUserU=userarray[u];
				
				String result = u+","+curUserU.sizeL()+","+curUserU.sizeR();
				System.out.println(result);
				
	  		    writeLinesToFile(logfile, new String[] {""+result}, true);

								
			}
			
			
			
			HashMap c2u = new HashMap(); 
			int [] likedcounter = new int [contentcount+1]; 
			
			
			for (int content=1; content<=contentcount; content++) {

					int counter = 0;
					for (int u=0; u<usercount; u++) {
						User curUserU=userarray[u];
				
						HashSet likeSetUserU = curUserU.getLikeList();
				
						if (likeSetUserU.contains(content)) {
							counter++;
						}
							
					}
				
					likedcounter[content] = counter; 
					
					c2u.put(content, counter);
					
			System.out.println("Content " + content + ": liked by " + counter + " users!");
			
			
			}
			
			
			
			List list = new LinkedList(c2u.entrySet());

			Collections.sort(list, new Comparator() {
				public int compare(Object o1, Object o2) {
					return ((Comparable) ((Map.Entry) (o1)).getValue())
	                                       .compareTo(((Map.Entry) (o2)).getValue());
				}
			});

                        
			for (int run=0; run<list.size(); run++)  //Ordered List of    Map content -> how often this content appeared in User L list
			{
				System.out.println(list.get(run));
			
			}
			
                        
                        //print Ordered List of    Map content -> how often this content appeared in User L list
			String logfile2 = "content_numberofuserlikes_"+System.currentTimeMillis()+"_"+usercount+"_"+contentcount+"_"+timesteps+"_simresults.log";
			
			
			
			for (int run=0; run<list.size(); run++) {
				
				String c2ustring= ((String) list.get(run).toString());
                        
				String [] splitted = c2ustring.split("=");
                                
	  		    writeLinesToFile(logfile2, new String[] {""+splitted[0]+","+splitted[1]}, true);

								
			}
                        
                        
			/*******************************************************************/
			
			
			// Anzahl der Nutzer, die genau k=i Content Elemente liken   //Text anders
			
			int [] b = new int [contentcount+1];  //THB Fehler
			
			for (int i=0; i<b.length; i++) {
				
				b[i]=0;
				
			}
			
			
			
			for (int i=0; i<b.length; i++) {
				
				int usercounter=0;
				
				for (int u=0; u<usercount; u++) {
					User curUserU=userarray[u];
			
					
					if (i==curUserU.getLikeList().size()  ) {
						usercounter++;
					}
					
				}
			
				b[i]=usercounter;                                    
				
			}

                       
                        //print ordered list of number of users that like exactly i=k content elements
                        
			String logfile3 = "numberofusers_thatlike_numberofcontents_"+System.currentTimeMillis()+"_"+usercount+"_"+contentcount+"_"+timesteps+"_simresults.log";

			for (int i=0; i<b.length; i++) { 
				       
                            System.out.println( b[i] + " users  like exactly " + i + " content elements.");
                        
                       //     u_like_nrc[ts][i]=b[i];  //if main loop includes this line 
                            
	  		    writeLinesToFile(logfile3, new String[] {""+b[i]+","+i}, true);
								
			}
                        
                        
			/***********************************************************************/
			
			
			//Anzahl der Content Elemente, die von k = likedcounter[i] Usern geliked werden
			
			int [] c = new int [usercount+1];
			
			for (int i=1; i<=contentcount; i++) {   //THB Fehler
				
				//likedcounter:  map content -> # users that like it
				
				c[likedcounter[i]]++;			
				
				
			}
			
			
                        //print ordered list of number of content elements that are liked by exactly i=k users
                        
			String logfile4 = "numberofcontents_likedby_numberofusers_"+System.currentTimeMillis()+"_"+usercount+"_"+contentcount+"_"+timesteps+"_simresults.log";

			for (int i=0; i<c.length; i++) { 
			
                            System.out.println(c[i] + " content elements liked by " +i + " users");
                            
                       //     c_likedby_u[ts][i]=c[i];    //if main loop includes this line 
                            
	  		    writeLinesToFile(logfile4, new String[] {""+c[i]+","+i}, true);
								
			}
                        
                        
                        /****************************************************************/
                         
                                
                                
                                
                                
				
		//	} //main loop   timesteps   //needed if simulation needs a log of each timestep
			
			
			
		/*	
		String logfile5 = "timesteps_numberofcontents_likedby_numberofusers_"+System.currentTimeMillis()+"_"+usercount+"_"+contentcount+"_"+timesteps+"_simresults.log";

                String help=" ";
                for (int ts=1; ts<=timesteps; ts++) {
			
                           // System.out.println(c[i] + " content elements liked by " +i + " users");
                            help=help+","+ts;
                            						
			}
                        
                        writeLinesToFile(logfile5, new String[] {""+help}, true);
                
                
                          
                for (int i=0; i<(contentcount+1); i++) { 
                    help=""+i;
			for (int ts=1; ts<=timesteps; ts++) {
			
                           // System.out.println(c[i] + " content elements liked by " +i + " users");
                         //   help=help+","+c_likedby_u[ts][i];
                            help=help+","+u_like_nrc[ts][i];						
			}
                        
                        writeLinesToFile(logfile5, new String[] {""+help}, true);
                }
		
		*/
			
			
		} else {
	        System.err.println("Number of users, contents and timesteps must be > 0.");

		}
		
	
		
		
	}

}
